using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Configuration;
using System.Collections.Specialized;
using System.ComponentModel;
using MindFactorial.LaunchPoint.Common;
using System.Security.Policy;
using System.Security;
using System.Security.Permissions;
using System.Net;
using System.Security.Principal;

namespace MindFactorial.LaunchPoint.Runtime
{
    /// <summary>
    /// Any class that needs to be run by LaunchPoint Runtime has to implement LaunchPointRunnableComponent.
    /// 
    /// <example >
    /// <code>
    ///  public class StartupApplication : LaunchPointRunnableComponent
    ///  {
    ///    ConsoleShell _shell;
    ///    public override int Startup(params string[] args)
    ///    {
    ///      _shell = new ConsoleShell();    
    ///      _shell.Show();
    ///       return 0; 
    ///    }   
    ///    public override void Shutdown()
    ///    {
    ///      _shell.Close();
    /// 
    ///     }
    /// </code>
    /// </example>
    /// 
    /// </summary>
    public abstract class LaunchPointApplication : ImmortalIPCObject 
    {
        
        private LaunchPointConfiguration _configuration;
        private bool _isshutdown = false;
        internal event BREConnectionRequestDelegate _breconnect = null;
        internal event AsyncBREConnectionRequestDelegate _breconnectAsync = null;
        internal event BroadcastRequestHandler _broadcast = null;
        internal event IncommingMessageDelegate _registerIncommingMessage = null;
        bool _isrunning = false;
        LaunchPointRuntimeContext _runtime_context = null;

        /// <summary>
        /// gets access to the runtime context for accessing the rules engine
        /// </summary>
        public LaunchPointRuntimeContext Context
        {
            get
            {
                return _runtime_context;
            }
        }

        /// <summary>
        /// Called when the runnable component is started.  This abstract function serves as
        /// the entrypoint of the application
        /// </summary>
        /// <param name="args">startup arguments to pass</param>
        /// <returns>return code</returns>
        public abstract int Startup(params string[] args);

        /// <summary>
        /// Gets the identity of the user currently running the specified component.  This
        /// method should be overriden in the sub class to implement custom security implementations
        /// as needed.  The default behaviour is to return the windows identity for this session
        /// </summary>
        /// <returns></returns>
        public virtual string GeCurrentRunnableUser()
        {
            //create security information to pass down
            WindowsIdentity identity = System.Security.Principal.WindowsIdentity.GetCurrent();
            return identity.Name;
        }


        /// <summary>
        /// Called when the runtime is shutdown to allow for open
        /// components to close elegantly
        /// </summary>
        public abstract void Shutdown();

        /// <summary>
        /// Called by the runtime when a Message is recieved through the p2p channel
        /// </summary>
        /// <param name="application"></param>
        /// <param name="filter"></param>
        /// <param name="Message"></param>
        public abstract void RecieveBroadcast(string application, string filter, string Message);

        /// <summary>
        /// Fired when a plugin is restarted due to an unhandled exception
        /// </summary>
        public abstract void UnhandledRecoveryStartup();

        /// <summary>
        /// Fired when a plugin is stopped due to an unhandled exception
        /// </summary>
        public abstract void UnhandledRecoveryShutdown();

        /// <summary>
        /// keeps the runnable running even when there is an error in a plugin
        /// </summary>
        public abstract void PersistAfterError();

        /// <summary>
        /// Displays a UI for the runnable components processing state, this is used 
        /// primarily in the asynchronous LaunchPointsaging pattern for calling the BRE
        /// </summary>
        public abstract void ShowWaitUI();

        /// <summary>
        /// Hides the UI displayed by ShowWaitUI
        /// </summary>
        public abstract void HideWaitUI();


        /// <summary>
        /// Displays a UI for the runnable components processing state, this is used 
        /// primarily in the asynchronous LaunchPointsaging pattern for calling the BRE
        /// </summary>
        public abstract void ShowWaitUI(object wait_handle);

        /// <summary>
        /// Hides the UI displayed by ShowWaitUI
        /// </summary>
        public abstract void HideWaitUI(object wait_handle);
        
        

        /// <summary>
        /// internal call to start or activate LaunchPointRunnableComponent
        /// </summary>
        /// <param name="configNode"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        internal int Run(LaunchPointConfiguration configuration, params string[] args)
        {
           
            //TODO: Any security to be enforced on the runnable can be done here
            //NamedPermissionSet ps = new NamedPermissionSet("hello", PermissionState.Unrestricted);
            //ps.AddPermission(new System.Net.WebPermission(PermissionState.None));
            //ps.Assert();
            this._runtime_context  = new LaunchPointRuntimeContext(this);
            _isrunning = true;
            _configuration = configuration;
            return Startup(args);
        }


        internal void RecoveryFromUnhandledException()
        {
            System.Windows.MessageBoxResult result = System.Windows.MessageBox.Show("An unhandled exception occured in the currently running plugin.  Would you like to unload the plugin ?", "Unhandled Exception", System.Windows.MessageBoxButton.YesNo);

            if (result != System.Windows.MessageBoxResult.Yes)
            {
                //call user code
                UnhandledRecoveryStartup();               
            }
            else
            {
                UnhandledRecoveryShutdown();
               
            }
        }

        internal void RegisterIncommingRequestHandler(IncommingMessageFiltrationHandler filter, IncommingMessageRequestHandler request_handler)
        {
            if (_registerIncommingMessage != null)
            {
                _registerIncommingMessage(filter, request_handler);
            }
        }



        /// <summary>
        /// Sends a request to the BRE layer
        /// </summary>
        /// <param name="session_id"></param>
        /// <param name="channel"></param>
        /// <param name="adapterID"></param>
        /// <param name="ruleID"></param>
        /// <param name="arguments"></param>
        /// <returns></returns>
        internal string BRERequest(Guid session_id, string channel, string adapterID, string ruleID, string arguments)
        {
            if (_breconnect != null)
            {
                return _breconnect(session_id, channel, adapterID, ruleID, arguments);               
            }
            return "No bre connection";
        }


        /// <summary>
        /// Sends an asynchronous request to the BRE layer
        /// </summary>
        /// <param name="session_id"></param>
        /// <param name="channel"></param>
        /// <param name="adapterID"></param>
        /// <param name="ruleID"></param>
        /// <param name="arguments"></param>
        /// <param name="acb"></param>
        /// <returns></returns>
        internal void BRERequest(Guid session_id, string channel, string adapterID, string ruleID, string arguments, AsyncRuleCompletedDelegate acb)
        {
            if (_breconnect != null)
            {
                
                AsyncRuleCompletedDelegate result = delegate(string response)
                {
                    //inform inheritors to hide their wait ui
                    this.HideWaitUI();
                    acb(response);
                };
                _breconnectAsync(session_id, channel, adapterID, ruleID, arguments, result);

                //inform inheritors to show their wait ui
                this.ShowWaitUI();
            }
            else
            {
                acb( "No bre connection");
            }
        }

        /// <summary>
        /// Broadcasts a Message to all items within the component
        /// </summary>
        /// <param name="application"></param>
        /// <param name="filter"></param>
        /// <param name="Message"></param>
        protected internal void Broadcast(string application, string filter, string Message)
        {
            if (_broadcast != null)
            {
                _broadcast(application, filter, Message);
            }
        }        
      
    

        /// <summary>
        /// Represents whether the Runnable component is shutdown or not 
        /// </summary>
        public bool IsShutdown
        {
            get
            {
                return _isshutdown;
            }
        }

        /// <summary>
        /// Gets a value indicating whether run has been called on this instance 
        /// already.  If shutdown is called, the running state will also return to false
        /// </summary>
        public bool IsRunning
        {
            get
            {
                return this._isrunning;
            }
        }
       
        /// <summary>
        /// Gets Client's configuration
        /// </summary>
        protected LaunchPointConfiguration ClientConfiguration
        {
            get
            {
                return _configuration;
            }
        }

        /// <summary>
        /// Gets Application Settings for LaunchPoint Runtime
        /// </summary>
        protected NameValueCollection RuntimeAppSettings
        {
            get
            {
                return ConfigurationManager.AppSettings;
            }
        }

       
       
    }

    
}
